/**
******************************************************************************************
* @file Reception.c
* @brief Management of the message's reception by TCP/IP.
* @date  4 mai 2015
* @author Benjamin Lancinot
*****************************************************************************************/
/* COPYRIGHT ****************************************************************************
*****************************************************************************************
* Copyright (c) 2015, Audrey LOISEAU and Benjamin LANCINOT.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
*    list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
********************************************************************************************/

#include "Reception.h"

/*******************************************************************************************
* PROTOTYPES
********************************************************************************************/

void Reception_destroyUtilities(Reception *);

void Reception_destroy(Reception **);

void Reception_start(Reception *);

void Reception_stop(Reception *);

Trame getID(char trame[]);

void * receiveMessage(Reception *);

/*******************************************************************************************
* FUNCTIONS
********************************************************************************************/

/**
 * @brief Constructor
 * @param mSocket Value of the right client socket
 * @param commandTab Pointer to all of the commands
 * @param cmdTabSize Number of commands
 * @return Pointer to a new Reception
 **/
Reception* Reception_create(Spreader* sp, int mSocket,Command* cmdTab[], int cmdTabSize){
        Reception* This = (Reception *) malloc(sizeof(*This));

        This->start = Reception_start;
        This->stop = Reception_stop;
        This->destroy = Reception_destroy;

        This->clientSocket = mSocket;
        This->spreader = sp;
	if (pthread_mutex_init(&This->mutex, NULL) != 0)
	{
		printf("\n mutex init failed\n");
	}
        //Save all commands in MessageHandler
	This->msgHandler = MessageHandler_create(cmdTab, cmdTabSize);
	printf("Reception creer\n");

	return This;

}

/**
 * @brief Destroy all of the components of Reception
 * @param This Pointer to the wanted Reception
 **/
void Reception_destroyUtilities(Reception * This){
	This->msgHandler->destroy(&This->msgHandler);
        if(This->carryOn){
		pthread_join(This->receiptThread,NULL);
        }
}

/**
 * @brief Destructor
 * @param This Double pointer to the wanted Reception
 **/
void Reception_destroy(Reception ** This){
        Reception_destroyUtilities(* This);
	if (*This) {
		free(*This);
		*This = NULL;
	}
}

/**
 * @brief Run the thread which permit to receive message by tcp/ip
 * @param This Pointer to the wanted Reception
 **/
void Reception_start(Reception *This){

	// The routine is available and the connection is establish
        //pthread_mutex_lock(&This->mutex);
	This->carryOn = true;
        //pthread_mutex_unlock(&This->mutex);

	// Creation of the thread which listen messages
        pthread_create(&This->receiptThread, 0,(void *) &receiveMessage,(Reception *) This);
}


/**
 * @brief Stop the reception properly
 * @param This Pointer to the wanted Reception
 **/
void Reception_stop(Reception *This){

        //pthread_mutex_lock(&This->mutex);
        This->carryOn = false;
        //pthread_mutex_unlock(&This->mutex);

        pthread_join(This->receiptThread,NULL);

}


/**
 * @brief Recover the frame about char sequence
 * @param trame Message in a char sequence
 * @return the message formatted in a Trame structure
 **/
Trame  getID(char trame[]){
	Trame extract;
	char *msg;

	// Recover the id
	msg = strtok(trame, "/");

	if (msg != NULL){
		// transform id in int
		extract.id = atoi(msg);
		// Recover the message
		msg = strtok(NULL, "-");
		extract.msg = msg;
	}
	else{
		extract.id = -1;
	}
	return extract;
}

/**
 * @brief Split string with delimitation
 * @param s The string
 * @param ct The delimitation
 * @return a tab with split string
 **/
char **str_split (char *s, const char *ct)
{
   char **tab = NULL;

   if (s != NULL && ct != NULL)
   {
      int i;
      char *cs = NULL;
      size_t size = 1;

      for (i = 0; (cs = strtok (s, ct)); i++)
      {
	      if (size <= (size_t) (i + 1))
         {
            void *tmp = NULL;

            size <<= 1;
            tmp = realloc (tab, sizeof (*tab) * size);
            if (tmp != NULL)
            {
               tab = tmp;
            }
            else
            {
               fprintf (stderr, "Memoire insuffisante\n");
               free (tab);
               tab = NULL;
               exit (EXIT_FAILURE);
            }
         }

         tab[i] = cs;
         s = NULL;
      }
      tab[i] = NULL;
   }
   return tab;
}


/**
 * @brief Function use by receiptThread to receiving message by TCP/IP
 * @param This Pointer to the wanted Reception
 * @return The final value for the thread
 **/
void * receiveMessage(Reception *This){
        fd_set readset;
	int retval;
        int nbData;
	Trame trame;
        int run =TRUE;
        int i;
	struct timeval tv;
	tv.tv_sec = 0;
	tv.tv_usec = 5000;

        while(run && This->carryOn){
                retval=0;
		FD_ZERO(&readset);
		FD_SET(This->clientSocket, &readset);

		retval = select(This->clientSocket +1,  &readset, NULL, NULL, &tv);
		if (retval>0){
			nbData = 0;
			char *charReceived= malloc(15*sizeof(char));
			nbData = recv(This->clientSocket,charReceived,sizeof(char)*15,0);
			if(nbData > 0){
				if(charReceived[0] != '~'){
					char** tab;
					tab=str_split(charReceived,"\n");
					//affichage du resultat
					for(i=0;tab[i]!=NULL;i++) {

						trame = getID(tab[i]);
						// Ask to message handler to do the right command
						if (trame.id > -1 && trame.id <9 && trame.msg != NULL){
                                                        if(strlen(trame.msg)> 0 && strlen(trame.msg) <9){
								This->msgHandler->handle(This->msgHandler, trame.id, trame.msg);
								This->spreader->warnAllClient(This->spreader,trame.id, trame.msg, This->clientSocket);
                                                        }
						}
					}
					free(tab);
				}
			}else{
				run = FALSE;
			}
			free(charReceived);
		}

		if(This->carryOn == false){
			run = FALSE;
		}

        }

        This->carryOn = false;
        return NULL;

}


